﻿namespace Blaze.Editor.Dev.DevPanels
{
    using System;
    using System.Linq;
    using System.Reflection;
    using Build;
    using UnityEditor;
    using UnityEngine;
    using BuildPipeline = Build.BuildPipeline;

    /// <summary>
    /// 打包功能面板。
    /// </summary>
    public class BuildDevPanel : DevPanel
    {
        /// <summary>
        /// 获取面板上显示的功能名称。
        /// </summary>
        public override string Name
        {
            get { return "构建"; }
        }

        /// <summary>
        /// 获取开发功能面板的显示优先级。
        /// </summary>
        public override int Priority
        {
            get { return 8888; }
        }

        /// <summary>
        /// 获取或设置已选中的打包目标索引。
        /// </summary>
        private int SelectedBuildTargetIndex
        {
            get
            {
                if (mSelectedBuildTargetIndex < 0)
                {
                    mSelectedBuildTargetIndex = ProjectEditorPrefs.GetInt("BuildDevPanel.SelectedBuildTargetIndex", -1);
                    if (mSelectedBuildTargetIndex < 0)
                        mSelectedBuildTargetIndex = Array.IndexOf(mBuildTargets, EditorUserBuildSettings.activeBuildTarget);
                }
                return mSelectedBuildTargetIndex;
            }
            set
            {
                if (mSelectedBuildTargetIndex == value)
                    return;
                if (value < 0)
                {
                    mSelectedBuildTargetIndex = value;
                    return;
                }
                if (!checkBuildTarget(mBuildTargets[value]))
                    return;
                mSelectedBuildTargetIndex = value;
                ProjectEditorPrefs.SetInt("BuildDevPanel.SelectedBuildTargetIndex", value);
            }
        }

        /// <summary>
        /// 获取或设置已选中的打包类型索引。
        /// </summary>
        private int SelectedBuildTypeIndex
        {
            get
            {
                if (mSelectedBuildTypeIndex < 0)
                    mSelectedBuildTypeIndex = ProjectEditorPrefs.GetInt("BuildDevPanel.SelectedBuildTypeIndex", 0);
                return mSelectedBuildTypeIndex;
            }
            set
            {
                if (mSelectedBuildTypeIndex == value)
                    return;
                mSelectedBuildTypeIndex = value;
                ProjectEditorPrefs.SetInt("BuildDevPanel.SelectedBuildTypeIndex", value);
                BuildSettings.Config = mBuildConfigs[value];
            }
        }

        /// <summary>
        /// 当需要绘制面板时调用此方法。
        /// </summary>
        public override void OnGUI()
        {
            EditorGUILayout.BeginVertical();

            EditorGUILayout.BeginHorizontal();
            GUILayout.Label("构建选项");
            GUILayout.FlexibleSpace();
            SelectedBuildTargetIndex = EditorGUILayout.Popup(SelectedBuildTargetIndex, mBuildTargetNames, mPopupStyle);
            SelectedBuildTypeIndex = EditorGUILayout.Popup(SelectedBuildTypeIndex, mBuildConfigNames, mPopupStyle);
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(16);

            EditorGUILayout.BeginVertical();
            for (var index = 0; index < mBuildPipelines.Length; index++)
                drawBuildPipeline(index);
            EditorGUILayout.EndVertical();

            EditorGUILayout.EndVertical();
        }

        /// <summary>
        /// 当面板需要初始化的时候调用。
        /// </summary>
        protected override void OnInitialize()
        {
            mHeaderStyle = new GUIStyle(GUISkinManager.Skin.box)
            {
                alignment = TextAnchor.MiddleLeft,
                padding = new RectOffset(16, 4, 4, 4),
                fontSize = 22,
                fixedHeight = 32,
            };

            mBodyStyle = new GUIStyle(GUISkinManager.Skin.button)
            {
                alignment = TextAnchor.MiddleRight,
                padding = new RectOffset(4, 16, 4, 4),
                fixedHeight = 20,
            };

            mPopupStyle = new GUIStyle(EditorStyles.popup)
            {
                fontSize = 12,
                fixedHeight = 20,
                fontStyle = FontStyle.Normal,
            };

            //构建配置
            var buildConfigType = typeof (BuildConfig);
            var query = from type in Assembly.GetExecutingAssembly().GetTypes()
                where buildConfigType.IsAssignableFrom(type) && !type.IsAbstract
                let config = (BuildConfig) Activator.CreateInstance(type)
                orderby config.DisplayOrder descending
                select config;
            mBuildConfigs = query.ToArray();
            mBuildConfigNames = mBuildConfigs.Select(config => config.Name).ToArray();

            if (BuildSettings.Config == null)
                BuildSettings.Config = mBuildConfigs.FirstOrDefault();

            //构建平台
            mBuildTargetNames = mBuildTargets.Select(target => target.ToString()).ToArray();
            SelectedBuildTargetIndex = Array.IndexOf(mBuildTargets, EditorUserBuildSettings.activeBuildTarget);

            //构建流程
            var queryForPipeline = from buildPipelineConfig in BlazeEditorConfig.Instance.BuildPipelines
                select BuildPipeline.Create(buildPipelineConfig);
            mBuildPipelines = queryForPipeline.ToArray();
        }

        private static bool checkBuildTarget(BuildTarget selectedBuildTarget)
        {
            if (selectedBuildTarget == EditorUserBuildSettings.activeBuildTarget)
                return true;

            var msg = string.Format("更换构建目标平台会需要重新导入所有资源，将会花费相当长一段时间，确认吗？\r\n\r\n{0} -> {1}", EditorUserBuildSettings.activeBuildTarget, selectedBuildTarget);
            if (EditorUtility.DisplayDialog("更换构建目标平台", msg, "确认", "取消"))
            {
                EditorUserBuildSettings.SwitchActiveBuildTarget(UnityEditor.BuildPipeline.GetBuildTargetGroup(selectedBuildTarget), selectedBuildTarget);
                return true;
            }
            return false;
        }

        private void drawBuildAction(BuildAction buildAction)
        {
            GUILayout.BeginHorizontal();
            GUILayout.Space(32);
            if (GUILayout.Button(buildAction.Name, mBodyStyle))
                buildAction.Execute();
            GUILayout.EndHorizontal();
        }

        private void drawBuildOption(BuildOption option)
        {
            GUILayout.BeginVertical();
            option.Draw();
            GUILayout.Space(8);
            GUILayout.EndVertical();
        }

        private void drawBuildPipeline(int index)
        {
            GUILayout.BeginVertical();

            var buildPipeline = mBuildPipelines[index];
            var isFoldout = getPipelineFoldoutState(index);

            GUILayout.Label(buildPipeline.Title, mHeaderStyle);
            var rect = GUILayoutUtility.GetLastRect();
            var headerRect = new Rect(rect.x, rect.y, rect.width - 64, rect.height);
            if (GUI.Button(headerRect, GUIContent.none, GUI.skin.label))
            {
                isFoldout = !isFoldout;
                setPipelineFoldoutState(index, isFoldout);
            }

            var executeRect = new Rect(rect.width - 64, rect.yMin + 4, 64, rect.height - 8);
            BeginBackgroundColor(Color.green);
            if (GUI.Button(executeRect, "执行"))
                buildPipeline.Execute();
            EndBackgroundColor();

            if (isFoldout)
            {
                foreach (var option in buildPipeline.Options)
                    drawBuildOption(option);
                foreach (var buildAction in buildPipeline.Actions)
                    drawBuildAction(buildAction);
            }
            GUILayout.EndVertical();
        }

        private GUIStyle mBodyStyle;
        private string[] mBuildConfigNames;
        private BuildConfig[] mBuildConfigs;
        private BuildPipeline[] mBuildPipelines;
        private string[] mBuildTargetNames;
        private readonly BuildTarget[] mBuildTargets = {BuildTarget.StandaloneWindows, BuildTarget.StandaloneWindows64, BuildTarget.Android, BuildTarget.iOS};
        private GUIStyle mHeaderStyle;
        private GUIStyle mPopupStyle;
        private int mSelectedBuildTargetIndex = -1;
        private int mSelectedBuildTypeIndex = -1;

        #region 展开状态

        private static bool getPipelineFoldoutState(int index)
        {
            return ProjectEditorPrefs.GetBool("BuildDevPanel.PipelineFoldout" + index);
        }

        private static void setPipelineFoldoutState(int index, bool isFoldout)
        {
            ProjectEditorPrefs.SetBool("BuildDevPanel.PipelineFoldout" + index, isFoldout);
        }

        #endregion
    }
}